package red.mlz.app.controller.material;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.threads.ThreadPoolExecutor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import red.mlz.app.domain.BaseContentValueVo;
import red.mlz.app.domain.BaseListVo;
import red.mlz.app.domain.BaseValueVo;
import red.mlz.app.domain.material.*;
import red.mlz.module.module.category.entity.Category;
import red.mlz.module.module.category.service.CategoryService;
import red.mlz.module.module.material.entity.Material;
import red.mlz.module.module.material.service.MaterialService;
import red.mlz.module.module.tag.entity.Tag;
import red.mlz.module.module.tag.service.TagService;
import red.mlz.module.utils.BaseUtils;
import red.mlz.module.utils.ImageUtils;
import red.mlz.module.utils.Response;
import red.mlz.module.utils.SpringUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

import static red.mlz.module.constant.RedisCacheConstant.MATERIAL_LIST_KEY;

/**
 * <p>
 * 分类表 前端控制器
 * </p>
 *
 * @author mlzred
 * @since 2025-04-03
 */
@RestController
@Slf4j
public class MaterialController {


    @Autowired
    private MaterialService materialService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private TagService tagService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    /**
     * 首页物料分页查询
     *
     * @return
     */
    @RequestMapping("/material/list")
    public Response materialList(@RequestParam(name = "wp", required = false) String wp,
                                 @RequestParam(name = "keyword", required = false) String keyword) {
        MaterialWpVo baseWp = new MaterialWpVo();
        if (!BaseUtils.isEmpty(wp)) {
            byte[] bytes = Base64.getUrlDecoder().decode(wp.getBytes(StandardCharsets.UTF_8));
            String realWp = new String(bytes, StandardCharsets.UTF_8);
            try {
                baseWp = JSON.parseObject(realWp, MaterialWpVo.class);
            } catch (Exception e) {
                return new Response(4004);
            }
        } else {
            baseWp.setPage(1);
            baseWp.setKey(keyword);
        }
        log.info("key:{}", String.format(MATERIAL_LIST_KEY, baseWp.getPage(), baseWp.getKey()));
        String redisCache = stringRedisTemplate.opsForValue().get(String.format(MATERIAL_LIST_KEY, wp, keyword));
        if (!BaseUtils.isEmpty(redisCache)) {
            BaseListVo result = JSON.parseObject(redisCache, BaseListVo.class);
            return new Response(1001, result);
        }

        String pageSize = SpringUtils.getProperty("application.pagesize");
        String categoryIds = null;
        if (StringUtils.isNotBlank(keyword)) {
            List<BigInteger> ids = categoryService.getIdsByName(keyword);
            categoryIds = StringUtils.join(ids, ",");
        }

        List<Material> materialList = materialService.getMaterialList(baseWp.getPage(), Integer.parseInt(pageSize), baseWp.getKey(), categoryIds);


        BaseListVo result = new BaseListVo();
        result.setIsEnd(Integer.parseInt(pageSize) > materialList.size());
        baseWp.setPage(baseWp.getPage() + 1);
        String jsonWp = JSONObject.toJSONString(baseWp);
        byte[] encodeWp = Base64.getUrlEncoder().encode(jsonWp.getBytes(StandardCharsets.UTF_8));
        result.setWp(new String(encodeWp, StandardCharsets.UTF_8).trim());

        List<MaterialFrontVO> list = new ArrayList<>();

        if (materialList.size() > 0) {
            String allCategoryIds = materialList.stream()
                    .filter(Objects::nonNull)  // 过滤掉 null
                    .map(Material::getCategoryId)
                    .distinct()
                    .map(String::valueOf)
                    .collect(Collectors.joining(","));
            List<Category> categoryList = categoryService.listByIds(allCategoryIds);
            Map<BigInteger, String> categoryMap = categoryList.stream().collect(Collectors.toMap(Category::getId, Category::getName));
            for (Material material : materialList) {
                BigInteger categoryId = material.getCategoryId();
                if (categoryMap.containsKey(categoryId)) {
                    MaterialFrontVO entry = new MaterialFrontVO();
                    entry.setMaterialId(material.getId());
                    entry.setName(material.getName());
                    entry.setCategoryName(categoryMap.get(categoryId));
                    if (!BaseUtils.isEmpty(material.getImageUrls())) {
                        int[] imageWidthAndHeight = ImageUtils.getImageWidthAndHeight(material.getImageUrls().split("\\$")[0]);
                        BaseValueVo arVo = new BaseValueVo();
                        double ar = (double) imageWidthAndHeight[0] / (double) imageWidthAndHeight[1];
                        String arStr = new BigDecimal(ar).setScale(2, RoundingMode.HALF_UP).toString(); // 四舍五入
                        arVo.setK("ar");
                        arVo.setV(arStr);
                        BaseValueVo urlVo = new BaseValueVo();
                        urlVo.setK("url");
                        urlVo.setV(material.getImageUrls().split("\\$")[0]);
                        List<BaseValueVo> image = new ArrayList<>();
                        image.add(arVo);
                        image.add(urlVo);
                        entry.setImage(image);
                    }
                    list.add(entry);
                }
            }
        }
        result.setList(list);
        // 设置缓存
        stringRedisTemplate.opsForValue().set(String.format(MATERIAL_LIST_KEY, baseWp.getPage() - 1, baseWp.getKey()),
                JSON.toJSONString(result), 30L, TimeUnit.MINUTES);
        return new Response(1001, result);
    }

    /**
     * 根据分类ID进行查询
     *
     * @param wp
     * @param cid
     * @return
     */
    @RequestMapping("/material/listbycid")
    public Response getMaterialListByCid(@RequestParam(name = "wp", required = false) String wp,
                                         @RequestParam(name = "cid") Integer cid) {
        MaterialWpVo baseWp = new MaterialWpVo();
        if (!BaseUtils.isEmpty(wp) && BaseUtils.isEmpty(cid)) {
            byte[] bytes = Base64.getUrlDecoder().decode(wp.getBytes(StandardCharsets.UTF_8));
            String realWp = new String(bytes, StandardCharsets.UTF_8);
            try {
                baseWp = JSON.parseObject(realWp, MaterialWpVo.class);
            } catch (Exception e) {
                return new Response(4004);
            }
        } else {
            baseWp.setPage(1);
            baseWp.setKey(cid.toString());
        }
        String pageSize = SpringUtils.getProperty("application.pagesize");
        List<Material> materialList = materialService.getMaterialList(baseWp.getPage(), Integer.parseInt(pageSize), null, baseWp.getKey());


        BaseListVo result = new BaseListVo();
        result.setIsEnd(Integer.parseInt(pageSize) > materialList.size());
        baseWp.setPage(baseWp.getPage() + 1);
        String jsonWp = JSONObject.toJSONString(baseWp);
        byte[] encodeWp = Base64.getUrlEncoder().encode(jsonWp.getBytes(StandardCharsets.UTF_8));
        result.setWp(new String(encodeWp, StandardCharsets.UTF_8).trim());
        List<MaterialListVo> list = new ArrayList<>();

        if (materialList.size() > 0) {
            for (Material material : materialList) {
                MaterialListVo entry = new MaterialListVo();
                entry.setMaterialId(material.getId());
                entry.setName(material.getName());
                if (!BaseUtils.isEmpty(material.getImageUrls())) {
                    int[] imageWidthAndHeight = ImageUtils.getImageWidthAndHeight(material.getImageUrls().split("\\$")[0]);
                    BaseValueVo arVo = new BaseValueVo();
                    double ar = (double) imageWidthAndHeight[0] / (double) imageWidthAndHeight[1];
                    String arStr = new BigDecimal(ar).setScale(2, RoundingMode.HALF_UP).toString(); // 四舍五入
                    arVo.setK("ar");
                    arVo.setV(arStr);
                    BaseValueVo urlVo = new BaseValueVo();
                    urlVo.setK("url");
                    urlVo.setV(material.getImageUrls().split("\\$")[0]);
                    List<BaseValueVo> image = new ArrayList<>();
                    image.add(arVo);
                    image.add(urlVo);
                    entry.setImage(image);
                }
                list.add(entry);
            }
        }
        result.setList(list);

        return new Response(1001, result);
    }


    @RequestMapping("/material/info")
    public Response getMaterialInfo(@RequestParam(name = "id") BigInteger id) {
        Material material = materialService.getById(id);
        Category category = categoryService.getById(material.getCategoryId());
        List<Tag> tagList = tagService.getByMaterialId(id);
        List<String> tag = tagList.stream().map(Tag::getName).collect(Collectors.toList());
        if (BaseUtils.isEmpty(material) || BaseUtils.isEmpty(category)) {
            return new Response(4004);
        }
        MaterialInfoVo entry = new MaterialInfoVo();
        entry.setMaterialId(material.getId());
        entry.setMaterialName(material.getName());
        entry.setCategoryName(category.getName());
        entry.setProductName(material.getProductName());
        entry.setMaterialCount(material.getMaterialCount());
        entry.setMaterialId(material.getId());
        entry.setMaterialId(material.getId());
        entry.setTag(tag);
        if (!BaseUtils.isEmpty(material.getImageUrls())) {
            List<List<BaseValueVo>> materialImages = new ArrayList<>();
            String[] materialUrls = material.getImageUrls().split("\\$");
            for (String materialUrl : materialUrls) {
                List<BaseValueVo> image = new ArrayList<>();
                int[] imageWidthAndHeight = ImageUtils.getImageWidthAndHeight(materialUrl);
                BaseValueVo arVo = new BaseValueVo();
                double ar = (double) imageWidthAndHeight[0] / (double) imageWidthAndHeight[1];
                String arStr = new BigDecimal(ar).setScale(2, RoundingMode.HALF_UP).toString(); // 四舍五入
                arVo.setK("ar");
                arVo.setV(arStr);
                BaseValueVo urlVo = new BaseValueVo();
                urlVo.setK("url");
                urlVo.setV(material.getImageUrls().split("\\$")[0]);
                image.add(arVo);
                image.add(urlVo);
                materialImages.add(image);
            }
            entry.setImages(materialImages);
        }
        if (!BaseUtils.isEmpty(category.getImageUrl())) {
            int[] imageWidthAndHeight = ImageUtils.getImageWidthAndHeight(category.getImageUrl());
            BaseValueVo arVo = new BaseValueVo();
            double ar = (double) imageWidthAndHeight[0] / (double) imageWidthAndHeight[1];
            String arStr = new BigDecimal(ar).setScale(2, RoundingMode.HALF_UP).toString(); // 四舍五入
            arVo.setK("ar");
            arVo.setV(arStr);
            BaseValueVo urlVo = new BaseValueVo();
            urlVo.setK("url");
            urlVo.setV(material.getImageUrls().split("\\$")[0]);
            List<BaseValueVo> image = new ArrayList<>();
            image.add(arVo);
            image.add(urlVo);
            entry.setCategoryImage(image);
        }
        try {
            List<BaseContentValueVo> contents = JSON.parseArray(material.getContent(), BaseContentValueVo.class);
            entry.setContent(contents);
        } catch (Exception cause) {
            // ignores
            return new Response(4004);
        }
        return new Response(1001, entry);
    }

}
